import _ from "lodash"
import {defineComponent, h, markRaw, nextTick, toRaw, unref} from "vue"
import {ElDialog, ElMessageBox, ElTag} from 'element-plus'
import {getLayoutOutline, getRuntimeCmp} from './CmpStore'
import JSON5 from 'json5'
import localforage from 'localforage'

export interface RestApiResult<T> {
    success: string,
    msg: string,
    data: T
}

export default class System {
    _ = _
    toRaw = toRaw
    unref = unref
    nextTick = nextTick
    defer = _.defer
    extend = _.extend
    cloneDeep = _.cloneDeep
    localforage = localforage

    JSON5 = JSON5
    json5 = JSON5

    /**
     * 全局当前按下的按钮（按下完毕之后会清空）
     */
    globalLoadingButtonInstance: any = null

    syncTime() {

    }

    getNowDate() {
        const date = new Date()
        const Y = date.getFullYear()
        const M = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
        const D = date.getDate() < 10 ? '0' + (date.getDate()) : date.getDate()
        return `${Y}-${M}-${D}`
    }

    formatTimestamp(timestamp) {
        const date = new Date(timestamp)
        const Y = date.getFullYear()
        const M = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
        const D = date.getDate()
        return `${Y}-${M}-${D}`
    }

    /**
     * 弹出用户必须点击确认的错误信息
     */
    showErrorDialog(msgOrTitle: string, msg?: string) {
        if (!msg) {
            console.error(msgOrTitle)
            ElMessageBox.alert(
                msgOrTitle,
                '错误',
                {
                    confirmButtonText: '关闭',
                    type: 'error',
                    draggable: true,
                }
            ).finally()
        } else {
            console.error(msg)
            ElMessageBox.alert(
                msg,
                msgOrTitle,
                {
                    confirmButtonText: '关闭',
                    type: 'error',
                    draggable: true,
                }
            ).finally()
        }
    }

    /**
     * 弹出用户必须确认的提示信息
     */
    showInfoDialog(content: string) {
        this.alert(content)
    }

    /**
     * 全局 “正在载入...” 对话框
     */
    showLoading() {
        if (this.globalLoadingHandle) {
            // 存在 "正在载入..." 对话框
            return
        }

        const _insId = _.uniqueId('_dlg')

        // @ts-ignore
        const {rootElementList} = window
        rootElementList.push({
            cmp: markRaw(LoadingDialog),
            props: {
                _insId: _insId,
            }
        })

        this.globalLoadingHandle = () => {
            _.remove(rootElementList, (item: any) => item.props._insId === _insId)
        }
    }

    /**
     * 关闭 “正在载入...” 对话框
     */
    clearLoading() {
        if (typeof this.globalLoadingHandle === 'function') {
            this.globalLoadingHandle()
        }
        this.globalLoadingHandle = null
    }

    /**
     * 在触发的按钮上显示 loading 状态
     * @return 关闭 loading 状态的函数
     */
    showLoadingIfButton(): () => void {
        if (!this.globalLoadingButtonInstance) {
            return
        }

        this.globalLoadingButtonInstance.loading = true

        const handle = this.globalLoadingButtonInstance

        return () => {
            handle.loading = false
        }
    }


    /**
     * 根据路径，异步打开某个组件，并拿到对话框的返回值
     * 原生 el-dialog 模式
     */
    showDialog(bizCmp, props: any = {}): Promise<any> {
        let title = props.title
        delete props.title
        let width = props.width
        delete props.width

        return new Promise<any>((resolve, reject) => {
            const _insId = _.uniqueId('_dlg')

            const dialogCmp = defineComponent({
                data() {
                    return {
                        title: title ?? '对话框',
                        isShow: true,
                        returnOk: false,
                        footerCmp: markRaw(() => undefined),
                        footerProp: {},
                        specHeight: 'auto',
                    }
                },
                render() {
                    const dialogInstance = this

                    return h(ElDialog,
                        {
                            modelValue: this.isShow,
                            appendToBody: true,
                            draggable: true,
                            modal: true,
                            destroyOnClose: true,
                            closeOnPressEscape: true,
                            title: this.title,
                            style: {
                                width: width || '90%',
                            },
                            onClosed() {
                                if (!dialogInstance.returnOk) {
                                    // 只要不是正常通过 returnOk 关闭的，都是返回 Promise.reject
                                    reject()
                                }
                                // @ts-ignore
                                const {rootElementList} = window
                                _.remove(rootElementList, (item: any) => item.props._insId === _insId)
                            },
                            onVnodeMounted(dialogInstance) {
                                // console.log('dialog', dialogInstance.el)
                            }
                        },
                        {
                            default(defaultProps) {
                                const targetProps = _.cloneDeep(props)

                                // if (specHeight) {
                                //     if (!targetProps.style) {
                                //         targetProps.style = {}
                                //     }
                                //     targetProps.style.height = specHeight
                                // }
                                return h(bizCmp, {
                                        style: {
                                            height: dialogInstance.specHeight
                                        },
                                        ...targetProps,
                                        _input: targetProps,
                                        onVnodeBeforeMount(bizInstance) {

                                            // 提取高度
                                            if (bizInstance.component.data.vjson?.height) {
                                                const specHeight = bizInstance.component.data.vjson.height
                                                // if (!targetProps.style) targetProps.style = {}
                                                // targetProps.style.height = specHeight ?? "500px"
                                                // dialogInstance.specHeight = specHeight ?? "500px"
                                                dialogInstance.specHeight = specHeight ?? "500px"
                                            }

                                            // 提取标题
                                            if (bizInstance.component.data.vjson?.title) {
                                                bizInstance.component.ctx.setTitle(bizInstance.component.data.vjson.title)
                                            }

                                            // 提取页脚组件
                                            const vjson = bizInstance.component.data.vjson
                                            const footerReference = vjson?.footerReference
                                            let footerDefine

                                            if (footerReference) {
                                                const defineList = getLayoutOutline(vjson)
                                                _.forEach(defineList, (define, propName) => {
                                                    if (define.isList) {
                                                        _.forEach(vjson [propName], item => {
                                                            if (item.reference === footerReference) {
                                                                footerDefine = _.cloneDeep(item)
                                                                /**
                                                                 * 删除当前位置的 vjson 元素
                                                                 * 将 footerDefine 在后续 slot.footer 处渲染
                                                                 */
                                                                // item.hidden = true
                                                                _.remove(vjson[propName], i => i === item)

                                                                _.defer(() => {
                                                                    const cmp = getRuntimeCmp(footerDefine)
                                                                    footerDefine.hidden = false

                                                                    dialogInstance.footerCmp = cmp
                                                                    dialogInstance.footerProp = {
                                                                        vjson: footerDefine,
                                                                        vcxt: bizInstance.component.data.vcxt
                                                                    }
                                                                })
                                                                return false
                                                            }
                                                        })
                                                    }
                                                })

                                                if (!footerDefine) {
                                                    system.showErrorDialog("can't found footerDefine:" + footerReference)
                                                }
                                            }
                                        },
                                        onVnodeMounted(bizInstance) {
                                            /** 一下代码用来调试
                                             console.log(bizInstance)
                                             window['bizCmp'] = bizInstance
                                             debugger
                                             console.log('vue', bizInstance.$el)
                                             */
                                        },
                                        onSetTitle(title) {
                                            dialogInstance.title = title
                                        },
                                        onOk(result) {
                                            // 通过收到业务组件 bizMixin.js 的 OK 事件，引起窗口关闭
                                            dialogInstance.isShow = false
                                            dialogInstance.returnOk = true
                                            dialogInstance.$nextTick(() => {
                                                resolve(result)
                                            })
                                        },
                                        onCloseDialog() {
                                            // 收到业务组件 bizMixin.js 的关闭请求
                                            dialogInstance.isShow = false
                                        },
                                    }
                                )
                            },
                            footer(props) {
                                return h(dialogInstance.footerCmp, dialogInstance.footerProp)
                            },
                            header({close, titleClass, key, titleId}) {

                                const headerTags = [
                                    h('span', {}, dialogInstance.title ?? ''),
                                ]
                                if (window['is_preview_mode']) {

                                } else {
                                    headerTags.push(
                                        h(ElTag, {
                                            type: "success",
                                            onClick() {
                                                // close()
                                                const f = bizCmp.__file
                                                if (f) {
                                                    system.openStudioModule(f.substring(f.indexOf('/wms-ui-pc/src/pages/') + 10))
                                                }
                                            }
                                        }, '进入设计'),
                                    )
                                }

                                return h('div', {
                                    class: titleClass + ' my-title',
                                }, headerTags)
                            }
                        }
                    )
                }
            })

            // @ts-ignore
            const {rootElementList} = window
            rootElementList.push({
                cmp: markRaw(dialogCmp),
                props: {
                    _insId: _insId,
                }
            })
        })
    }


    /**
     * 信息提示内容，强提示，必须用户点击确认
     * @param msg 消息内容
     */
    alert(msg) {
        console.info(msg)
        ElMessageBox.alert(msg, '提示', {
            confirmButtonText: '关闭',
            draggable: true,
            // 1110000
        })
    }

    /**
     * 轻量级提示信息
     * @param message 消息内容
     */
    msg(message: string) {
        // ElMessage(cc)
        console.log(message)

        const $body = $('body')

        $body.find('[xtype=tooltip]').remove()
        const $w = $(
            '<div xtype="tooltip" class="yvan-msg yvan-anim yvan-anim-00">' +
            '  <div class="yvan-msg-content">' +
            _.escape(message) +
            '</div></div>'
        )
        $body.append($w)

        const iframeWidth = $w.parent().width() as number
        const iframeHeight = $w.parent().height() as number

        const windowWidth = $w.width() as number
        const windowHeight = $w.height() as number

        let setWidth = (iframeWidth - windowWidth) / 2
        let setHeight = (iframeHeight - windowHeight) / 2
        if (iframeHeight < windowHeight || setHeight < 0) {
            setHeight = 0
        }
        if (iframeWidth < windowWidth || setWidth < 0) {
            setWidth = 0
        }
        $w.css({left: setWidth, top: setHeight})
        setTimeout(() => {
            $w.remove()
        }, 3000)
    }

    /**
     * 弹出确认对话框
     * @param msg 消息内容
     */
    confirm(msg): Promise<void> {
        return new Promise((resolve, reject) => {
            ElMessageBox.confirm(msg, '再次确认',
                {
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    icon: markRaw(QuestionFilled),
                }
            ).then(() => {
                resolve()

            }).catch(() => {
                reject()
            })
        })
    }

    /**
     * 判断是否为空
     * @param value
     */
    isEmpty(value?: any): boolean {
        if (typeof value === 'undefined' || value === null) {
            return true;
        }
        if (typeof value === 'number' && isNaN(value)) {
            return true;
        }
        if (value === 'N/A') {
            return true;
        }
        return ("" + value).trim().length <= 0;
    }

    /**
     * 替换内部结构中，所有 N/A
     */
    replaceNA(obj) {
        if (obj === 'N/A') {
            return ''
        }

        if (_.isArray(obj)) {
            _.forEach(obj, (value, idx) => {
                if (value === 'N/A') {
                    obj[idx] = ''
                } else {
                    if (typeof value === "string" && /^-?\d*\.\d+$/.test(value)) {
                        let count = 0;
                        for (let i = value.length - 1; i > 0; i--) {
                            if (value[i] === "0") {
                                count++
                            } else if (value[i] === ".") {
                                count++
                                break;
                            } else {
                                break;
                            }
                        }
                        obj[idx] = value.substr(0, value.length - count);
                    } else {
                        this.replaceNA(value)
                    }
                }
            })
        } else if (_.isPlainObject(obj)) {
            _.forOwn(obj, (value, key) => {
                if (value === 'N/A') {
                    obj[key] = ''
                } else {
                    if (typeof value === "string" && /^-?\d*\.\d+$/.test(value)) {

                        let count = 0;
                        for (let i = value.length - 1; i > 0; i--) {
                            if (value[i] === "0") {
                                count++
                            } else if (value[i] === ".") {
                                count++
                                break;
                            } else {
                                break;
                            }
                        }
                        obj[key] = value.substr(0, value.length - count);
                    } else {
                        this.replaceNA(value)
                    }
                }
            })
        }
    }
}


function _deepFill(parentJson, customSetting, callback, extCallback, lotCallback) {
    if (_.isArray(parentJson)) {
        // 数组
        _.forEach(parentJson, value => {
            // 递归查找
            _deepFill(value, customSetting, callback, extCallback, lotCallback)
        })
    } else if (_.isObject(parentJson)) {
        // 普通对象
        const uiBlock = parentJson["uiBlock"]
        if (uiBlock) {
            // 有 uiBlock 属性
            if (parentJson["xtype"] === "aggrid") {
                // 表格处理
                if (!parentJson["columns"]) {
                    parentJson["columns"] = []
                }
                const columns = parentJson["columns"]
                _.forEach(columns, (col, idx) => {
                    if (!col.dataIndex || _.toString(col.dataIndex).includes('.')) {
                        // 包含特殊符号，或没有名称的字段，不列入管理范围
                        return
                    }
                    const uiKey = col.header ?? col.dataIndex ?? col.field
                    // 在 customSetting 中找到是否包含 uiBlock.uiKey 的自定义属性描述
                    const setting = _.get(customSetting, uiBlock + '.' + uiKey)
                    if (setting) {
                        callback(parentJson, col, uiBlock, uiKey, setting, idx)
                    }
                });

                const extCmpList = _.get(customSetting, 'ext.' + uiBlock)
                if (extCmpList) {
                    extCallback(parentJson, uiBlock, extCmpList)
                }

                lotCallback(parentJson, uiBlock)
                return

            } else if (parentJson['xtype'] === 'form') {
                // 表单处理
                if (!_.isArray(parentJson['items'])) {
                    parentJson['items'] = []
                }

                const items = parentJson['items']
                _.forEach(items, (item, idx) => {
                    const uiKey = item["uiKey"] ?? item['fieldLabel']
                    if (!uiKey || uiKey === '-') {
                        return
                    }
                    const setting = _.get(customSetting, uiBlock + '.' + uiKey)
                    if (setting) {
                        callback(parentJson, item, uiBlock, uiKey, setting, idx)
                    }
                });

                const extCmpList = _.get(customSetting, 'ext.' + uiBlock)
                if (extCmpList) {
                    extCallback(parentJson, uiBlock, extCmpList)
                }
                lotCallback(parentJson, uiBlock)
                return

            } else if (parentJson['xtype'] === 'tabs') {
                // 选项卡
                if (!_.isArray(parentJson['items'])) {
                    parentJson['items'] = []
                }
                const items = parentJson['items']
                _.forEach(items, (item, idx) => {
                    if (item.xtype !== 'tabpanel') {
                        // 选项卡只读子选项卡
                        return
                    }
                    const uiKey = item['title']
                    if (!uiKey || uiKey === '-') {
                        return
                    }
                    const setting = _.get(customSetting, uiBlock + '.' + uiKey)
                    if (setting) {
                        callback(parentJson, item, uiBlock, uiKey, setting, idx)
                    }
                    _deepFill(item.items, customSetting, callback, extCallback, lotCallback)
                });
                lotCallback(parentJson, uiBlock)
                return

            } else if (parentJson['xtype'] === 'toolbar') {
                // 工具条
                if (!_.isArray(parentJson['items'])) {
                    parentJson['items'] = []
                }

                const items = parentJson['items']
                _.forEach(items, (item, idx) => {
                    if (item.xtype !== 'button') {
                        // 工具条组件只读取按钮
                        return
                    }
                    const uiKey = item["uiKey"] ?? item['text']
                    if (!uiKey || uiKey === '-') {
                        return
                    }
                    const setting = _.get(customSetting, uiBlock + '.' + uiKey)
                    if (setting) {
                        callback(parentJson, item, uiBlock, uiKey, setting, idx)
                    }
                });
                lotCallback(parentJson, uiBlock)
                return
            }
        }
        _.forOwn(parentJson, (value, key) => {
            // 递归查找
            if (_.isObject(value)) {
                _deepFill(value, customSetting, callback, extCallback, lotCallback)
            }
        })
    }
}

function _deepAnalysis(parentJson, uiBlocks, uiInfos) {
    if (_.isArray(parentJson)) {
        // 数组
        _.forEach(parentJson, value => {
            // 递归查找
            _deepAnalysis(value, uiBlocks, uiInfos)
        })
    } else if (_.isObject(parentJson)) {
        // 普通对象
        const uiBlock = parentJson["uiBlock"]
        if (uiBlock) {
            if (uiBlocks.has(uiBlock)) {
                system.msg(`uiBlock=[${uiBlock}]出现重复`)
            }
            uiBlocks.add(uiBlock);

            if (parentJson["xtype"] === "aggrid") {
                // 表格处理
                const columns = parentJson["columns"]
                if (_.isArray(columns)) {
                    _.forEach(columns, (col, idx) => {
                        if (!col.dataIndex || _.toString(col.dataIndex).includes('.')) {
                            // 包含特殊符号，或没有名称的字段，不列入管理范围
                            return
                        }
                        uiInfos.push({
                            ui_block: uiBlock,
                            ui_key: col.header ?? col.dataIndex ?? col.field,
                            dm_field_order: idx,
                            dm_field_label: col.header,
                            dm_field_ui: {...col},
                        });
                    });
                }
                return

            } else if (parentJson['xtype'] === 'form') {
                // 表单处理
                const items = parentJson['items']
                if (_.isArray(items)) {
                    _.forEach(items, (item, idx) => {
                        const uiKey = item["uiKey"] ?? item['fieldLabel']
                        if (!uiKey || uiKey === '-') {
                            return
                        }
                        uiInfos.push({
                            ui_block: uiBlock,
                            ui_key: uiKey,
                            dm_field_order: idx,
                            dm_field_label: item.fieldLabel,
                            dm_field_ui: {...item},
                        });
                    });
                }
                return

            } else if (parentJson['xtype'] === 'tabs') {
                // 选项卡
                const items = parentJson['items']
                if (_.isArray(items)) {
                    _.forEach(items, (item, idx) => {
                        if (item.xtype !== 'tabpanel') {
                            // 选项卡只读子选项卡
                            return
                        }
                        const uiKey = item['title']
                        if (!uiKey || uiKey === '-') {
                            return
                        }
                        uiInfos.push({
                            ui_block: uiBlock,
                            ui_key: uiKey,
                            dm_field_order: idx,
                            dm_field_label: item.title,
                            dm_field_ui: {...item},
                        });
                        _deepAnalysis(item.items, uiBlocks, uiInfos)
                    });
                }
                return

            } else if (parentJson['xtype'] === 'toolbar') {
                // 工具条
                const items = parentJson['items']
                if (_.isArray(items)) {
                    _.forEach(items, (item, idx) => {
                        if (item.xtype !== 'button') {
                            // 工具条组件只读取按钮
                            return
                        }
                        const uiKey = item["uiKey"] ?? item['text']
                        if (!uiKey || uiKey === '-') {
                            return
                        }
                        uiInfos.push({
                            ui_block: uiBlock,
                            ui_key: uiKey,
                            dm_field_order: idx,
                            dm_field_label: item.text,
                            dm_field_ui: {...item},
                        });
                    });
                }
                return
            }
        }
        _.forEach(parentJson, value => {
            // 递归查找
            if (_.isObject(value)) {
                _deepAnalysis(value, uiBlocks, uiInfos)
            }
        })
    }
}


// const LoadingDialog = defineComponent({
//     data() {
//         return {
//             isShow: true,
//         }
//     },
//     render() {
//         return h(ElDialog,
//             {
//                 modelValue: this.isShow,
//                 appendToBody: true,
//                 draggable: true,
//                 modal: true,
//                 destroyOnClose: true,
//                 closeOnPressEscape: false,
//                 title: '正在载入',
//                 style: {
//                     width: '90%'
//                 },
//                 onClosed() {
//                     // @ts-ignore
//                     const {rootElementList} = window
//                     _.remove(rootElementList, (item: any) => item.prop._insId === _insId)
//                 },
//                 onVnodeMounted(dialogInstance) {
//                     // console.log('dialog', dialogInstance.el)
//                 }
//             },
//             [
//                 h('div', null,
//                     [
//                         h(renderIcon('Loading')),
//                         h('span', {
//                             style: {
//                                 color: 'red',
//                                 fontSize: '22px',
//                             }
//                         }, '请稍等...'),
//                     ])
//             ]
//         )
//     }
// })